package com.ctrip.ec.biz.dao.member;

import com.ctrip.ec.biz.entity.member.MemberSession;
import com.ctrip.ec.dal.DaoBase;
import com.ctrip.ec.biz.entity.member.MemberEntity;
import com.ctrip.ec.dal.DbAccess;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class MemberDao extends DaoBase<MemberEntity> {

    public MemberDao() {
        super(MemberEntity.class);

    }

    public MemberDao(DbAccess db) {
        super(MemberEntity.class, db);

    }

    public static final Map<String, MemberSession> sessionMap = new ConcurrentHashMap<>();
    public static final ExecutorService thPool = Executors.newFixedThreadPool(1);

    private final static Logger logger = LoggerFactory.getLogger(MemberDao.class);

    @PostConstruct
    private void init() {

        thPool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("thread start");
                while (true) {
                    if (Thread.currentThread().isInterrupted()) {
                        break;
                    }
                    Calendar visitTime = Calendar.getInstance();
                    List<String> expireKey = new ArrayList<String>();
                    for (Map.Entry<String, MemberSession> entry : sessionMap.entrySet()) {
                        visitTime.setTime(entry.getValue().getLastVisit());
                        visitTime.add(Calendar.MINUTE, 30);//30分钟后过期
                        Long now = System.currentTimeMillis();
                        if (now > visitTime.getTime().getTime()) {
                            expireKey.add(entry.getKey());
                        }
                    }
                    if(expireKey.size()>0) {
                        logger.info("clear " + expireKey.size() + " expire keys");
                        expireKey.forEach(t -> {
                            sessionMap.remove(t);
                        });
                    }
                    try {
                        Thread.sleep(1000 * 60 * 30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });
    }

    public  Map<String, MemberSession> sessions(){
        return sessionMap;
    }

    public  MemberSession entityByToken(String token) throws SQLException {
        if (Strings.isNullOrEmpty(token)) {
            return null;
        }

        if (!sessionMap.containsKey(token)) {
            logger.info("sessionMap has no token :"  + token);

            String sql = "select * from " + this.getTableName() + " where auth_token=?";
            List<MemberEntity> list = this.db.query(MemberEntity.class, sql, token);
            if (list.size() > 0) {
                logger.info("sessionMap add token success :" + token);

                MemberSession memberSession = new MemberSession(list.get(0));
                sessionMap.put(memberSession.getAuthToken(), memberSession);
            } else {
                logger.info("can not take member|" + token + "|" + sql );
                return null;
            }
        }
        return sessionMap.get(token);
    }

    public MemberEntity entityByMobile(String mobile) throws SQLException {
        String sql = "select * from " + this.getTableName() + " where mobile = ?";
        List<MemberEntity> list = this.db.query(MemberEntity.class, sql, mobile);
        if (list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }
    }

    public MemberEntity entityWithLock(Long id) throws SQLException {
        String sql = "select * from " + this.getTableName() + " where id = ? for update";
        List<MemberEntity> list = this.db.query(MemberEntity.class, sql, id);
        if (list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }

    }

    public void refreshSession(MemberEntity memberEntity) throws SQLException {
        memberEntity = this.entity(memberEntity.getId());//取一下最新的数据
        MemberSession memberSession = new MemberSession(memberEntity);
        memberSession.setLastVisit(new Timestamp(System.currentTimeMillis()));
        sessionMap.put(memberSession.getAuthToken(), memberSession);
    }
}
